
/**组合式继承的 new。基于 "借用构造函数" 和 "原型链继承" 的组合方式。
 * - 这种方式解决了原型继承的问题：父类构造函数中的所有属性成为原型属性，并且被所有实例共享。
 * - 同时也解决了借用构造函数（对象伪装、经典继承）的问题：子类构造函数可以向父类构造函数传递参数，
 * - 每个实例都拥有独立的父类构造函数的属性，不再共享父类构造函数的属性，但子类无法直接访问父类的原型。（但可以通过 Object.getPrototypeOf() 方法或 __proto__ 属性）
 * @param Parent 被继承的类的构造函数
 * @param args 构造函数的参数，用数组形式传递
 * @returns 实例
 * @example
 * function Person(name: string, age: number) {
 *     this.name = name;
 *     this.age = age;
 *     // return { aaa: 'aaa' } // 构造函数的返回值如果是一个对象，将会用这个对象，来代替刚刚构造出来的对象
 * }
 * const child = myNew(Person, ['Tom', 16])
 * console.log(child);// Person {name: 'Tom', age: 16}
 */
const combinedNew = function <T extends (...args: any) => any>(Parent: T, args: Parameters<T>) {
    const obj = Object.create(Parent.prototype); // 创建一个以父类原型为原型的新对象
    // 下面这段是其它方法：
    // const obj = {};
    // (obj as any).__proto__ = Parent.prototype  //Tip: __proto__是非标准属性，所以可以用 Object.setPrototypeOf(obj, Parent.prototype); 但是这个性能不如__proto__
    const result = Parent.apply(obj, args)
    if (result && typeof result === 'object') return result //构造函数的返回值如果是一个对象，将会用这个对象，来代替刚刚构造出来的对象  （如果是普通数据类型，就还是用构造出来的那个对象）
    return obj
}
export default combinedNew


//#region 组合式继承概念
// function Parent(name?: string) {
//     this.name = name;
// }
// //在父亲的原型上创建一个方法
// Parent.prototype.sayHello = function () {
//     console.log('Hello, ' + this.name);
// };
// //定义孩子类
// function Child(name: string, age: number) {
//     Parent.call(this, name);//盗用构造函数，实现组合继承
//     this.age = age;
// }

// Child.prototype = new Parent();//原型赋值
// Child.prototype.constructor = Child; //构造函数赋值

// Child.prototype.sayAge = function () {
//     console.log('I am ' + this.age + ' years old');
// };
// const child = new Child('Alice', 10);
// console.log('child', child); //在浏览器控制台看原型
// child.sayHello(); // 输出：Hello, Alice
// child.sayAge(); // 输出：I am 10 years old
//#endregion
